package biz.datalk.industrialland.common.aspect;

import biz.datalk.industrialland.common.exception.ValidateException;
import biz.datalk.industrialland.common.result.UnifyResult;
import biz.datalk.industrialland.common.result.UnifyResultCode;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import java.util.ArrayList;
import java.util.List;

/**
 * @author tarofang@163.com
 * @date 2022-10-31
 */
@Aspect
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
public class ParamCheckAspect {
    private static final Logger log = LoggerFactory.getLogger(ParamCheckAspect.class);

    @Pointcut("@annotation(biz.datalk.industrialland.common.aspect.annotation.ParamCheck)")
    public void logPointCut() {
    }


    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        Object errResult = this.handleBindResultError(point);
        if (errResult != null) {
            return errResult;
        }
        return point.proceed();
    }

    /**
     * 返回值为 null 表示校验正常
     * 返回值不是 null 表示校验失败
     */
    private Object handleBindResultError(JoinPoint point) {
        Object[] args = point.getArgs();
        if (ArrayUtils.isEmpty(args)) {
            return null;
        }

        List<BindingResult> bindingResults = new ArrayList<>();
        BindingResult tmpBindingResult;
        for (Object arg : args) {
            if (arg instanceof BindingResult) {
                tmpBindingResult = (BindingResult) arg;
                bindingResults.add(tmpBindingResult);
            }
        }
        if (CollectionUtils.isEmpty(bindingResults)) {
            return null;
        }

        boolean isDebugEnabled = log.isDebugEnabled();
        for (BindingResult bindingResult : bindingResults) {
            if (!bindingResult.hasErrors()) {
                continue;
            }
            if (isDebugEnabled) {
                StringBuilder errorInfo = new StringBuilder();
                List<FieldError> errors = bindingResult.getFieldErrors();//获取字段参数不合法的错误集合
                for (FieldError error : errors) {
                    errorInfo.append("[").append(error.getField()).append(":").append(error.getDefaultMessage()).append("]");
                }
                if (log.isDebugEnabled()) {
                    log.debug("{}", errorInfo);
                }
            }

            FieldError fieldError = bindingResult.getFieldError();
            String errMsg = fieldError == null ? "参数校验异常" : fieldError.getDefaultMessage();

            MethodSignature signature = (MethodSignature) point.getSignature();
            Class<?> returnType = signature.getReturnType();
            String name = returnType.getName();
            if (StringUtils.equals(name, UnifyResult.class.getName())) {
                return UnifyResult.fail(UnifyResultCode.VALIDATE_ERROR, errMsg);
            }
            throw new ValidateException(errMsg);

        } //~ end of "for (BindingResult bindingResult : bindingResults) {"

        return null;
    }
}
